package com.fin.zw.aiqas.service;

import com.fin.zw.aiqas.entity.QRuleInfo;
import com.fin.zw.aiqas.entity.QTaskInfo;
import com.fin.zw.aiqas.entity.RuleInfo;
import com.fin.zw.aiqas.entity.TaskInfo;
import com.fin.zw.aiqas.enums.LogicalCalculus;
import com.fin.zw.aiqas.enums.Status;
import com.fin.zw.aiqas.enums.TaskStatus;
import com.fin.zw.aiqas.enums.TaskType;
import com.fin.zw.aiqas.job.ElasticJobManager;
import com.fin.zw.aiqas.model.request.TaskInfoRequest;
import com.fin.zw.aiqas.model.response.TaskInfoResponse;
import com.fin.zw.aiqas.model.session.SessionModel;
import com.fin.zw.aiqas.repository.RuleInfoRepository;
import com.fin.zw.aiqas.repository.TaskInfoRepository;
import com.fin.zw.aiqas.util.BadRequestException;
import com.fin.zw.aiqas.util.BeanUtil;
import com.querydsl.core.BooleanBuilder;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.thymeleaf.util.SetUtils;

import java.util.*;

@Service
public class TaskInfoService {

    private final static Logger log = LoggerFactory.getLogger(TaskInfoService.class);

    @Autowired
    private TaskInfoRepository taskInfoRepository;
    @Autowired
    private RuleInfoRepository ruleInfoRepository;

    @Autowired
    private ElasticJobManager elasticJobManager;

    @Autowired
    private TaskInfoJobService taskInfoJobService;

    @Autowired
    private ExecuteTaskInfoService executeTaskInfoService;

    /**
     * 增加任务信息
     * @param request
     * @param sessionModel
     */
    public void add(TaskInfoRequest request, SessionModel sessionModel) {
        TaskInfo taskInfo = new TaskInfo();
        BeanUtils.copyProperties(request, taskInfo);
        taskInfo.setOperatorRealName(sessionModel.getUserName());
        taskInfo.setOperatorId(sessionModel.getUserId());
        taskInfo.setCreateTime(new Date());
        //查询list里面的质检规则ID之后转set
        Set<RuleInfo> ruleInfoSet = getRuleInfoBySceId(request.getScenesInfoId());
        if (!SetUtils.isEmpty(ruleInfoSet)) {
            taskInfo.setRuleInfoSet(ruleInfoSet);
        }
        //通话时长，不是自定义时 置空 endNum
        if (StringUtils.isNotBlank(String.valueOf(taskInfo.getDurationLogic()))) {
            if (!taskInfo.getDurationLogic().equals(LogicalCalculus.CUSTOM)) {
                taskInfo.setEndNum(null);
            }
        }

        if (StringUtils.isNotBlank(String.valueOf(taskInfo.getTaskType()))) {
            if (taskInfo.getTaskType().equals(TaskType.MANUAL)) {
                //任务类型为手动任务的清空 taskCron；
                taskInfo.setTaskCron(null);
                //定时任务为手动，置空自动质检时间类型
                taskInfo.setCheckTimeType(null);
                //手动设置 runStatus
                taskInfo.setRunStatus(TaskStatus.READY);
            }
            taskInfo.setStatus(Status.STOP);
        }
        taskInfoRepository.save(taskInfo);
    }

    /**
     * 根据场景id查询对应的规则
     *
     * @param sceId
     * @return
     */
    public Set<RuleInfo> getRuleInfoBySceId(Long sceId) {
        BooleanBuilder builder = new BooleanBuilder();
        QRuleInfo qRuleInfo = QRuleInfo.ruleInfo;
        builder.and(qRuleInfo.scenesInfo.id.eq(sceId));
        builder.and(qRuleInfo.states.eq(Status.START));
        Iterator<RuleInfo> iterator = ruleInfoRepository.findAll(builder).iterator();
        Set<RuleInfo> result = new HashSet<>();
        while (iterator.hasNext()) {
            RuleInfo ruleInfo = iterator.next();
            result.add(ruleInfo);
        }
        return result;
    }

    /**
     * 根据任务ID删除信息
     * @param id
     */
    public void delete(Long id) {
        TaskInfo taskInfo = taskInfoRepository.findById(id).orElseThrow(() -> new BadRequestException("", "当前查询的数据不存在"));
        //任务只有
        if (taskInfo.getRunStatus().equals(TaskStatus.READY)) {
            taskInfoRepository.delete(taskInfo);
        } else {
            throw new BadRequestException("", "执行过的任务不允许删除！");
        }
    }

    /**
     * 修改
     * @param request
     * @
     */
    public void update(TaskInfoRequest request, SessionModel sessionModel) {
        TaskInfo taskInfo = taskInfoRepository.findById(request.getId()).orElseThrow(() -> new BadRequestException("", "当前修改的数据不存在"));
        //判断手动还是自动任务  自动不做限制，可以修改
        if (taskInfo.getTaskType().equals(TaskType.MANUAL)) {//手动
            if (!taskInfo.getRunStatus().equals(TaskStatus.READY)) {
                throw new BadRequestException("", "只有就绪状态的任务才能修改！");
            }
        }
        BeanUtil.copyProperties(request, taskInfo);
        Set<RuleInfo> ruleInfoSet = getRuleInfoBySceId(request.getScenesInfoId());
        taskInfo.setRuleInfoSet(ruleInfoSet);
        taskInfo.setUpdateRealName(sessionModel.getUserName());
        taskInfo.setUpdateUserId(sessionModel.getUserId());
        taskInfo.setUpdateTime(new Date());
        if (taskInfo.getTaskType().equals(TaskType.MANUAL)) {
            //定时任务为手动，置空自动质检时间类型
            taskInfo.setCheckTimeType(null);
            //任务类型为手动任务的清空 taskCron；
            taskInfo.setTaskCron(null);
        }
        //通话时长，不是自定义时指控 endNum
        if (!taskInfo.getDurationLogic().equals(LogicalCalculus.CUSTOM)) {
            taskInfo.setEndNum(null);
        }
        //任务类型为手动任务的清空 taskCron
        if (taskInfo.getTaskType().equals(TaskType.MANUAL)) {
            taskInfo.setTaskCron("");
        }
        taskInfoRepository.save(taskInfo);
    }

    public List<TaskInfo> fetchAll() {
        List<TaskInfo> taskInfoList = taskInfoRepository.findAll();
        return taskInfoList;
    }

    /**
     * 根据条件查询-分页
     * @param request
     * @param pageable
     * @return
     */
    public Page<TaskInfo> fetchPage(TaskInfoRequest request, Pageable pageable, SessionModel sessionModel) {
        BooleanBuilder builder = new BooleanBuilder();
        QTaskInfo qTaskInfo = QTaskInfo.taskInfo;
        builder.and(qTaskInfo.operatorId.eq(sessionModel.getUserId()));
        //任务名称
        if(StringUtils.isNotEmpty(request.getName())){
            builder.and(qTaskInfo.name.like("%".concat(request.getName()).concat("%")));
        }
        //任务类型 全部/自动/手动
        if (request.getTaskType() != null) {
            builder.and(qTaskInfo.taskType.eq(request.getTaskType()));
        }
        //任务状态 就绪/执行/暂停/完成
        if(null != request.getRunStatus()){
            builder.and(qTaskInfo.runStatus.eq(request.getRunStatus()));
        }
        //开始时间 start - end
        if(request.getStartTime() != null && request.getStartTimeE() != null){
            builder.and(qTaskInfo.startTime.between(request.getStartTime(), request.getStartTimeE()));
        }
        //完成时间 start - end
        if(request.getEndTimeS() != null && request.getEndTime() != null ){
            builder.and(qTaskInfo.endTime.between(request.getEndTimeS(), request.getEndTime()));
        }
        //创建人
        if (StringUtils.isNotEmpty(request.getOperatorRealName())) {
            builder.and(qTaskInfo.operatorRealName.like("%".concat(request.getOperatorRealName().concat("%"))));
        }
        //创建时间 start - end
        if(request.getCreateTime() != null && request.getCreateTimeEnd() != null ){
            builder.and(qTaskInfo.createTime.between(request.getCreateTime(), request.getCreateTimeEnd()));
        }
        Page<TaskInfo> taskPage = taskInfoRepository.findAll(builder, pageable);
        return taskPage;
    }

    /**
     * 根据ID查询对应任务信息
     * @param id
     * @return
     */
    public TaskInfoResponse queryById(Long id){
        TaskInfo taskInfo = taskInfoRepository.findById(id).orElseThrow(() -> new BadRequestException("", "没有查到任务 ID 为 " + id + " 的任务信息。。。"));
        TaskInfoResponse response = new TaskInfoResponse();
        BeanUtils.copyProperties(taskInfo, response);
        response.setRuleInfoSet(taskInfo.getRuleInfoSet());
        return response;
    }


    //@Transactional
    public void executeTask(Long taskId) throws Exception {
        log.info("开始执行任务，id为：" + taskId);
        Optional<TaskInfo> optional = taskInfoRepository.findById(taskId);
        if (!optional.isPresent()) {
            throw new BadRequestException("", "推送的任务信息不存在！+");
        }
        TaskInfo taskInfo = optional.get();
        if (taskInfo.getStatus().equals(Status.START)) {
            if (taskInfo.getTaskType().equals(TaskType.MANUAL)) { //手动
                if (!taskInfo.getRunStatus().equals(TaskStatus.READY)) {
                    throw new BadRequestException("", "任务名称：" + taskInfo.getName() + "的运行状态不是就绪状态，不能再次执行该任务");
                }
                taskInfo.setRunStatus(TaskStatus.EXCUTING);
                taskInfoRepository.save(taskInfo);
                log.info("开始执行手动任务id:" + taskId);
                executeTaskInfoService.sendTaskInfo(taskId);
            } else {//自动
                elasticJobManager.initJob(taskId);
            }
        }
    }

    /**
     * 修改任务状态
     *
     * @param taskId
     */
    public void updateStatus(Long taskId) {
        Optional<TaskInfo> optional = taskInfoRepository.findById(taskId);
        if (!optional.isPresent()) {
            throw new BadRequestException("", "推送的任务信息不存在！+");
        }
        TaskInfo taskInfo = optional.get();
        if (taskInfo.getStatus().equals(Status.START)) {
            if (taskInfo.getTaskType().equals(TaskType.MANUAL)
                    && taskInfo.getRunStatus().equals(TaskStatus.EXCUTING)) {
                throw new BadRequestException("", "执行状态任务不允许暂停！");
            } else if (taskInfo.getTaskType().equals(TaskType.MANUAL)
                    && taskInfo.getRunStatus().equals(TaskStatus.FINISH)) {
                throw new BadRequestException("", "执行完成的任务不允许暂停！");
            }
            taskInfo.setRunStatus(TaskStatus.FINISH);
            taskInfo.setStatus(Status.STOP);
        } else {
            taskInfo.setRunStatus(TaskStatus.READY);
            taskInfo.setStatus(Status.START);
        }
        taskInfoRepository.save(taskInfo);
    }
}
